package org.demo.client;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;

/**
 * 作者： lzw<br/>
 * 创建时间：2019-01-15 11:19 <br/>
 */
public class DateTypeAdapter extends TypeAdapter<Date> {

    private static final String HH_mm_ss = "HH:mm:ss";
    private static final String yyyy_MM_dd = "yyyy-MM-dd";
    private static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
    private static final String yyyy_MM_dd_HH_mm = "yyyy-MM-dd HH:mm";
    private static String[] parsePatterns = {HH_mm_ss, yyyy_MM_dd, yyyy_MM_dd_HH_mm_ss, yyyy_MM_dd_HH_mm, "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm"};

    private final Class<? extends Date> dateType;

    public DateTypeAdapter(Class<? extends Date> dateType) {
        this.dateType = verifyDateType(dateType);
    }

    private static Class<? extends Date> verifyDateType(Class<? extends Date> dateType) {
        if (dateType != Date.class && dateType != java.sql.Date.class && dateType != Timestamp.class) {
            throw new IllegalArgumentException("Date type must be one of " + Date.class + ", " + Timestamp.class + ", or " + java.sql.Date.class + " but was " + dateType);
        }
        return dateType;
    }

    @Override
    public void write(JsonWriter out, Date value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        String dateFormatAsString = DateFormatUtils.format(value, yyyy_MM_dd_HH_mm_ss);
        out.value(dateFormatAsString);
    }

    @Override
    public Date read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }
        Date date = deserializeToDate(in.nextString());
        if (dateType == Date.class) {
            return date;
        } else if (dateType == Timestamp.class) {
            return new Timestamp(date.getTime());
        } else if (dateType == java.sql.Date.class) {
            return new java.sql.Date(date.getTime());
        } else {
            // This must never happen: dateType is guarded in the primary constructor
            throw new AssertionError();
        }
    }

    private Date deserializeToDate(String s) {
        long timeStamp = NumberUtils.toLong(s, -1);
        if (timeStamp == -1) {
            try {
                return DateUtils.parseDate(s, parsePatterns);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        } else {
            // 1547451835
            // 1547523749669
            // 1000000000
            if (timeStamp / 1000000000L < 10) {
                timeStamp *= 1000;
            }
            return new Date(timeStamp);
        }
    }
}
